package com.example.ecommercemarketing.processor.impl;

import com.example.ecommercemarketing.dto.MarketingElementsDTO;
import com.example.ecommercemarketing.dto.ProductDTO;
import com.example.ecommercemarketing.dto.UserDTO;
import com.example.ecommercemarketing.handler.MarketingElementsHandler;
import com.example.ecommercemarketing.processor.MarketingElementsProcessor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 营销素材处理器类
 *
 * <p>实现了MarketingElementsProcessor接口，提供了营销素材处理的通用逻辑</p>
 * <p>采用责任链模式处理营销素材，各个实例bean需提供具体的handlerList实现</p>
 * <p>处理器会按顺序尝试每个handler，直到找到合适的营销素材</p>
 */
@Data
@Slf4j
public class MarketingElementsCommonProcessor implements MarketingElementsProcessor {
    @Autowired
    @Qualifier("marketingThreadPool")
    protected ThreadPoolExecutor marketingThreadPool;

    @Resource(name = "productCenterThreadPoolTtl")
    protected Executor productCenterThreadPoolTtl;
    /**
     * 营销素材处理器链
     * <p>包含多个MarketingElementsHandler实现类</p>
     * <p>子类需要通过构造函数注入具体的处理器列表</p>
     * <p>处理器将按照列表顺序依次尝试处理</p>
     */
    protected List<MarketingElementsHandler> handlerList;

    /**
     * 处理商品营销素材【未使用多线程】
     * <p>遍历商品列表，为每个商品寻找合适的营销素材</p>
     *
     * @param products 待处理的商品列表
     * @param user     用户信息，用于个性化营销
     * @return 营销素材列表，每个商品对应一个营销素材
     * @deprecated 已弃用【未使用多线程】，使用process方法替代【使用多线程】
     */
    //@Override
    @Deprecated
    public List<MarketingElementsDTO> processOld(List<ProductDTO> products, UserDTO user) {
        // 初始化结果集合
        List<MarketingElementsDTO> result = new ArrayList<>();

        // 遍历所有商品
        for (ProductDTO product : products) {
            // 按顺序尝试处理器链中的每个handler
            for (MarketingElementsHandler handler : handlerList) {
                // 获取当前handler处理的营销素材
                MarketingElementsDTO elements = handler.handle(product, user);

                // 如果handler返回有效结果，则使用该结果
                if (elements != null) {
                    result.add(elements);
                    // 找到一个有效handler后跳出循环，不再尝试后续handler
                    break;
                }
            }
        }

        return result;
    }

    /**
     * 处理商品营销素材【使用多线程】
     * <p>遍历商品列表，为每个商品寻找合适的营销素材</p>
     *
     * @param products 待处理的商品列表
     * @param user     用户信息，用于个性化营销
     * @return 营销素材列表，每个商品对应一个营销素材
     */
    @Override
    public List<MarketingElementsDTO> process(List<ProductDTO> products, UserDTO user) {
        // 使用线程安全的集合（CopyOnWriteArrayList适合读多写少的场景）
        List<MarketingElementsDTO> result = new CopyOnWriteArrayList<>();

        //遍历所有商品,创建并执行所有异步任务
        List<CompletableFuture<Void>> futures = products.stream()
                .map(product -> CompletableFuture
                        // 提交任务到线程池（使用自定义线程池而不是默认的ForkJoinPool）
                        .supplyAsync(() -> {
                            // 按顺序尝试处理器链中的每个handler
                            for (MarketingElementsHandler handler : handlerList) {
                                //获取当前handler处理的营销素材
                                MarketingElementsDTO elements = handler.handle(product, user);
                                if (elements != null) {
                                    addProductInfo(elements, product);
                                    //找到一个有效handler后跳出循环，不再尝试后续handler
                                    return elements;
                                }
                            }
                            return null; // 所有handler都不匹配时返回null
                        }, marketingThreadPool)
                        // 异步处理结果（使用whenComplete避免阻塞线程）
                        .thenAcceptAsync(elements -> {
                            //如果handler返回有效结果，则使用该结果
                            if (elements != null) {
                                result.add(elements);
                            }
                        }, productCenterThreadPoolTtl)
                        // 异常处理（记录日志但继续执行）
                        .exceptionally(ex -> {
                            log.error("营销素材处理任务异常，商品ID: {}, 用户ID: {}, 异常信息: {}", product.getId(), user.getUserId(), ex.getMessage(), ex);
                            return null;
                        })
                ).collect(Collectors.toList());

        try {
            // 使用allOf等待所有任务完成（带总超时控制）
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .get(10, TimeUnit.SECONDS); // 总超时时间10秒
        } catch (InterruptedException e) {
            // 线程中断
            log.error("线程中断异常: 线程名={}, 用户ID={}", Thread.currentThread().getName(), user.getUserId(), e);
            Thread.currentThread().interrupt(); // 保持中断状态
        } catch (Exception e) {
            // 其他异常处理
            log.error("营销素材处理任务超时或发生异常，用户ID: {}, 异常信息: {}", user.getUserId(), e.getMessage(), e);
        }


        // 构建商品ID到索引(在列表中的位置)的映射，用于后续的排序
        Map<Long, Integer> productIdToIndex = new HashMap<>(products.size());
        for (int i = 0; i < products.size(); i++) {
            ProductDTO product = products.get(i);
            if (product != null) {
                productIdToIndex.put(product.getId(), i);
            }
        }

        // 按原始商品列表顺序排序，并过滤空结果
        List<MarketingElementsDTO> sortedResult = result.stream()
                .filter(Objects::nonNull)
                .sorted(Comparator.comparingInt(dto -> productIdToIndex.getOrDefault(dto.getProductId(), Integer.MAX_VALUE)))
                .collect(Collectors.toList());

        log.debug("处理结果：{}", sortedResult);

        return sortedResult;
    }

    /**
     * 添加商品信息到营销素材DTO
     *
     * @param elements 营销素材DTO
     * @param product  商品信息
     */
    private static void addProductInfo(MarketingElementsDTO elements, ProductDTO product) {
        elements.setProductId(product.getId());
        elements.setProductTitle(product.getName());
    }


}
